/***************************************************************
* Name:      MCSkinnerMultiApp.cpp
* Purpose:   Code for Application Class
* Author:    Paril ()
* Created:   2011-11-05
* Copyright: Paril ()
* License:
**************************************************************/

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__

#include "MCSkinnerMultiApp.h"
#include "noname.h"
#include "Model.h"
#include <GL/glew.h>
#include <IL/il.h>

#include <boost/filesystem.hpp>

#include "Resources.h"
#include "Skin.h"
#include "RendererBase.h"
#include "ImmediateRenderer.h"
#include "ClientArrayRenderer.h"
#include "Settings.h"
#include "FixedArray.h"
#include "ViewMode.h"
#include "ToolMenuIDs.h"
#include "Background.h"

static GLuint CurrentSkin;
Model *CurrentModel;

class wxGLCanvasSubClass: public wxGLCanvas {
public:
	void Render();
	wxGLContext* _context;
	Skin *_lastSkin;
	GLuint _toolboxUpNormal, _toolboxUpHover, _toolboxDownNormal, _toolboxDownHover, _grassTop, _previewPaint, _alphaTex;
	RendererBase *_renderer;

	float _2dCamOffsetX, _2dCamOffsetY, _2dZoom;
	float _3dRotationX, _3dRotationY, _3dZoom;
	float _animationTime;
	ViewMode CurrentViewMode;

	bool _mouseIn3D, _mouseIsDown;
	int _mouseButton;
	wxPoint _mousePoint;
	class BackgroundMenuItem *_currentBackground;

	class ITool *_selectedTool;

	wxGLCanvasSubClass(wxWindow* parent);
	~wxGLCanvasSubClass()
	{
		delete _context;
	}
	void InitGL();
	void Paintit(wxPaintEvent& event);
	void OnSize(wxSizeEvent& event);

	void MakeCurrent()
	{
		_context->SetCurrent(*this);
	}

	wxRect _currentViewport;
	void Setup3D(wxRect viewport)
	{
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();

		glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
		//var mat = OpenTK.Matrix4d.Perspective(45, (double)viewport.Width / (double)viewport.Height, 0.01, 100000);
		//GL.MultMatrix(ref mat);
		gluPerspective(45, (double)viewport.width / (double)viewport.height, 1, 1000);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		_currentViewport = viewport;
	}

	void Setup2D(wxRect viewport)
	{
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();

		glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
		glOrtho(0, viewport.width, viewport.height, 0, -1, 1);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		_currentViewport = viewport;
	}

	UndoBuffer *GetCurrentUndoBuffer()
	{
		if (_lastSkin == NULL)
			return NULL;

		return &_lastSkin->Undo;
	}

	void DrawPlayer2D(int tex, Skin *skin, bool pickView);
	void DrawPlayer3D(int tex, Skin *skin, bool pickView);
	void SetPreview();

	void CheckMouse(int y);

	void OnMouseLeftDown(wxMouseEvent &ev);
	void OnMouseMove(wxMouseEvent &ev);
	void OnMouseLeftUp(wxMouseEvent &ev);

	float GetToolScale();
	void RotateView(wxPoint delta, float factor);
	void ScaleView(wxPoint delta, float factor);

	int GetCameraRotateButton();
	int GetCameraZoomButton();

protected:
	DECLARE_EVENT_TABLE()
};

class BackgroundMenuItem : public wxMenuItem
{
public:
	Background		Overlay;

	BackgroundMenuItem(wxMenu *parent, int id, const Background &background) :
		wxMenuItem(parent, id, background.Name, background.Name, wxITEM_CHECK),
		Overlay(background)
	{
	};
};

wxGLCanvasSubClass *glCanvas;

#include "CameraTool.h"

void RepaintTimer::Notify()
{
	_ctrl->_animationTime += 0.24f;
	_ctrl->Paintit(wxPaintEvent());
}

BEGIN_EVENT_TABLE(wxGLCanvasSubClass, wxGLCanvas)
	EVT_PAINT    (wxGLCanvasSubClass::Paintit)
	EVT_SIZE	 (wxGLCanvasSubClass::OnSize)
	END_EVENT_TABLE()

wxGLCanvasSubClass::wxGLCanvasSubClass(wxWindow *parent) :
	wxGLCanvas(parent, wxID_ANY,  (const int*)NULL, wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas")),
	_lastSkin(NULL),
	_2dCamOffsetX(0),
	_2dCamOffsetY(0),
	_2dZoom(8),
	_3dRotationX(0),
	_3dRotationY(0),
	_3dZoom(-80),
	_animationTime(0),
	CurrentViewMode(ViewMode_Perspective),
	_mouseIsDown(false),
	_selectedTool(new CameraTool()),
	_mouseButton(0)
{
	_context = new wxGLContext(this);

	SetBackgroundStyle(wxBG_STYLE_CUSTOM);

	Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxGLCanvasSubClass::OnMouseLeftDown), NULL, this);
	Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxGLCanvasSubClass::OnMouseLeftUp), NULL, this);
	Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxGLCanvasSubClass::OnMouseLeftDown), NULL, this);
	Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxGLCanvasSubClass::OnMouseLeftUp), NULL, this);
	Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxGLCanvasSubClass::OnMouseLeftDown), NULL, this);
	Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxGLCanvasSubClass::OnMouseLeftUp), NULL, this);
	Connect(wxEVT_MOTION, wxMouseEventHandler(wxGLCanvasSubClass::OnMouseMove), NULL, this);
}

MyFrame1* frame;

void RecurseAddItems(wxTreeCtrl *tree, const wxTreeItemId &parent, const boost::filesystem3::path &path)
{
	for (boost::filesystem3::directory_iterator end, dir(path); dir != end; ++dir)
	{
		if (boost::filesystem3::is_regular_file((*dir).path()))
		{
			wxTreeItemId id = tree->AppendItem(parent, (*dir).path().filename().stem().string());
			Skin *skin = new Skin((*dir).path().string(), tree, id);
			skin->SetImages();
		}
		else if (boost::filesystem3::is_directory((*dir).path()))
		{
			wxTreeItemId parentId = tree->AppendItem(parent, (*dir).path().stem().string());
			RecurseAddItems(tree, parentId, (*dir).path());
		}
	}
}

static bool _initialized = false;
void wxGLCanvasSubClass::InitGL()
{
	_context->SetCurrent(*this);

	glewInit();
	ilInit();

	glClearColor(0.52f, 0.80f, 0.84f, 1/*GlobalSettings::BackgroundColor*/);

	glEnable(GL_TEXTURE_2D);
	glShadeModel(GL_SMOOTH);                        // Enable Smooth Shading
	glClearDepth(1.0f);                         // Depth Buffer Setup
	glEnable(GL_DEPTH_TEST);                        // Enables Depth Testing
	glDepthFunc(GL_LEQUAL);                         // The Type Of Depth Testing To Do
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);          // Really Nice Perspective Calculations
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_FRONT);

	_toolboxUpNormal = LoadGLImage(RESOURCE(buttong, png));
	_toolboxUpHover = LoadGLImage(RESOURCE(buttong_2, png));
	_toolboxDownNormal = LoadGLImage(RESOURCE(buttong_down, png));
	_toolboxDownHover = LoadGLImage(RESOURCE(buttong_down2, png));

	_grassTop = LoadGLImage("grass.png");
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	std::vector<Background> overlays;
	for (boost::filesystem3::recursive_directory_iterator end, dir("./Overlays/"); dir != end; ++dir)
	{
		if (boost::filesystem3::is_regular_file((*dir).path()) &&
			wxString((*dir).path().string()).EndsWith(".png"))
		{
			try
			{
				GLuint image = LoadGLImage(wxString((*dir).path().string()));
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

				overlays.push_back(Background(wxString((*dir).path().filename().stem().string()), image));
			}
			catch (std::exception)
			{
				//MessageBox.Show(this, string.Format(GetLanguageString("B_MSG_OVERLAYERROR"), file));
			}
		}
	}

	for (size_t i = 0; i < overlays.size(); ++i)
	{
		BackgroundMenuItem *menuItem = (BackgroundMenuItem*)frame->view2DOverlayMenuItem->Append(new BackgroundMenuItem(NULL, TOOL_BACKGROUND_ITEM + i, overlays[i]));

		if (menuItem->Overlay.Name == GlobalSettings::LastBackground)
		{
			menuItem->Check(true);
			glCanvas->_currentBackground = menuItem;
		}

		//item.Click += item_Clicked;
		//item.Tag = i;

		//backgroundsToolStripMenuItem.DropDownItems.Add(item);
	}

	glGenTextures(1, &_previewPaint);
	glGenTextures(1, &CurrentSkin);
	glGenTextures(1, &_alphaTex);

	{
		byte arra[64 * 32 * 4];
		BindTexture(_previewPaint);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, arra);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

		BindTexture(CurrentSkin);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, arra);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	}

	{
		byte arra[4 * 4 * 4];
		byte *d = arra;

		for (int y = 0; y < 4; ++y)
			for (int x = 0; x < 4; ++x)
			{
				bool dark = ((x + (y & 1)) & 1) == 1;

				if (dark)
					*((int*)d) = (80 << 0) | (80 << 8) | (80 << 16) | (255 << 24);
				else
					*((int*)d) = (127 << 0) | (127 << 8) | (127 << 16) | (255 << 24);
				d += 4;
			}

		BindTexture(_alphaTex);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, arra);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	}

	if (glewGetExtension("GL_EXT_vertex_array"))
		_renderer = new ClientArrayRenderer();
	else
		_renderer = new ImmediateRenderer();

	frame->_skipListbox = false;

	_initialized = true;
}

void wxGLCanvasSubClass::OnSize(wxSizeEvent& event)
{	
	if (_initialized)
		this->Paintit(wxPaintEvent());
}

void wxGLCanvasSubClass::Paintit(wxPaintEvent& WXUNUSED(event))
{
	Render();
}

float wxGLCanvasSubClass::GetToolScale()
{
	const float baseSize = 200.0f;
	return baseSize / GetSize().x;
}

int wxGLCanvasSubClass::GetCameraRotateButton()
{
	//if (_selectedTool == _tools[(int)Tools.Camera])
		return wxMOUSE_BTN_LEFT;
	//else
	//	return MouseButtons.Right;
}

int wxGLCanvasSubClass::GetCameraZoomButton()
{
	//if (_selectedTool == _tools[(int)Tools.Camera])
		return wxMOUSE_BTN_RIGHT;
	//else
	//	return MouseButtons.Middle;
}

void wxGLCanvasSubClass::RotateView(wxPoint delta, float factor)
{
	if (CurrentViewMode == ViewMode_Perspective || (CurrentViewMode == ViewMode_Hybrid && _mouseIn3D))
	{
		_3dRotationY += (float)(delta.x * GetToolScale()) * factor;
		_3dRotationX += (float)(delta.y * GetToolScale()) * factor;
	}
	else
	{
		_2dCamOffsetX += delta.x / _2dZoom;
		_2dCamOffsetY += delta.y / _2dZoom;
	}
}

void wxGLCanvasSubClass::ScaleView(wxPoint delta, float factor)
{
	if (CurrentViewMode == ViewMode_Perspective || (CurrentViewMode == ViewMode_Hybrid && _mouseIn3D))
		_3dZoom += (float)(-delta.y * GetToolScale()) * factor;
	else
	{
		_2dZoom += -delta.y / 25.0f;

		if (_2dZoom < 1)
			_2dZoom = 1;
	}
}

void wxGLCanvasSubClass::CheckMouse(int y)
{
	if (y > (GetSize().y / 2))
		_mouseIn3D = true;
	else
		_mouseIn3D = false;
}

void wxGLCanvasSubClass::OnMouseLeftDown(wxMouseEvent &ev)
{
	Skin *skin = _lastSkin;

	if (skin == NULL)
		return;

	CheckMouse(ev.GetY());

	float halfWidth = GetSize().x / 2.0f;
	float halfImgWidth = 56.0f / 2.0f;

	wxRect rect(halfWidth - halfImgWidth, 0, halfImgWidth * 2, 22);

	_mousePoint = ev.GetPosition();

	if (rect.Contains(_mousePoint))
	{
		/*if (splitContainer4.SplitterDistance == 0)
			_opening = true;
		else
			_opening = false;

		_animTimer.Start();*/
		return;
	}

	_mouseIsDown = true;
	_mouseButton = ev.GetButton();

	if (_mouseButton == wxMOUSE_BTN_LEFT)
	{
		wxPoint p;

		/*if (GetPick(e.X, e.Y, ref p))
			_selectedTool.Tool.BeginClick(_lastSkin, p, e);
		else*/
			_selectedTool->/*Tool.*/BeginClick(_lastSkin, wxPoint(-1, -1), ev);
		/*UseToolOnViewport(e.X, e.Y);*/
	}
	else
	{
		//_tools[(int)Tools.Camera].Tool.BeginClick(_lastSkin, Point.Empty, e);
		_selectedTool->/*Tool.*/BeginClick(_lastSkin, wxPoint(-1, -1), ev);
	}
}

void wxGLCanvasSubClass::OnMouseMove(wxMouseEvent &ev)
{
	Skin *skin = _lastSkin;

	if (skin == NULL)
		return;

	if (_mouseIsDown)
	{
		if (_mouseButton == wxMOUSE_BTN_LEFT)
		{
			_selectedTool->/*Tool.*/MouseMove(_lastSkin, ev);
			//UseToolOnViewport(e.X, e.Y);
		}
		else
		{
		//	_tools[(int)Tools.Camera].Tool.MouseMove(_lastSkin, e);
			_selectedTool->/*Tool.*/MouseMove(_lastSkin, ev);
		}

		Render();
	}

	_mousePoint = ev.GetPosition();
}

void wxGLCanvasSubClass::OnMouseLeftUp(wxMouseEvent &ev)
{
	Skin *skin = _lastSkin;

	if (skin == NULL)
		return;

	if (_mouseIsDown)
	{
		if (_mouseButton == wxMOUSE_BTN_LEFT)
		{
			BindTexture(CurrentSkin);
			fixedarray<int> tempArray (skin->GetWidth() * skin->GetHeight());
			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempArray);

			if (_selectedTool->/*Tool.*/EndClick(tempArray, skin, ev))
			{
				frame->SetCanSave(true);
				skin->Dirty = true;
				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, skin->GetWidth(), skin->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tempArray);
			}
		}
		else
		{
		//	_tools[(int)Tools.Camera].Tool.EndClick(null, _lastSkin, e);
		}
	}

	_mouseButton = 0;
	_mouseIsDown = false;
}

void wxGLCanvasSubClass::DrawPlayer2D(int tex, Skin *skin, bool pickView)
{
	if (!pickView && GlobalSettings::AlphaCheckerboard)
	{
		BindTexture(_alphaTex);

		glBegin(GL_QUADS);
		glTexCoord2f(0, 0);
		glVertex2f(0, 0);
		glTexCoord2f(_currentViewport.width / 32.0f, 0);
		glVertex2f(_currentViewport.width, 0);
		glTexCoord2f(_currentViewport.width / 32.0f, _currentViewport.height / 32.0f);
		glVertex2f(_currentViewport.width, _currentViewport.height);
		glTexCoord2f(0, _currentViewport.height / 32.0f);
		glVertex2f(0, _currentViewport.height);
		glEnd();
	}

	if (skin != NULL)
		BindTexture(tex);

	glPushMatrix();

	glTranslatef((_currentViewport.width / 2) + -_2dCamOffsetX, (_currentViewport.height / 2) + -_2dCamOffsetY, 0);
	glScalef(_2dZoom, _2dZoom, 1);

	if (pickView)
		glDisable(GL_BLEND);
	else
		glEnable(GL_BLEND);

	glTranslatef((_2dCamOffsetX), (_2dCamOffsetY), 0);
	if (skin != NULL)
	{
		float w = skin->GetWidth();
		float h = skin->GetHeight();
		glBegin(GL_QUADS);
		glTexCoord2f(0, 0); glVertex2f(-(skin->GetWidth() / 2), -(skin->GetHeight() / 2));
		glTexCoord2f(1, 0); glVertex2f((skin->GetWidth() / 2), -(skin->GetHeight() / 2));
		glTexCoord2f(1, 1); glVertex2f((skin->GetWidth() / 2), (skin->GetHeight() / 2));
		glTexCoord2f(0, 1); glVertex2f(-(skin->GetWidth() / 2), (skin->GetHeight() / 2));
		glEnd();
	}

	if (!pickView && GlobalSettings::TextureOverlay && skin != NULL &&
		_currentBackground->Overlay.Texture != 0)
	{
		BindTexture(_currentBackground->Overlay.Texture);

		glBegin(GL_QUADS);
		glTexCoord2f(0, 0); glVertex2f(-(skin->GetWidth() / 2), -(skin->GetHeight() / 2));
		glTexCoord2f(1, 0); glVertex2f((skin->GetWidth() / 2), -(skin->GetHeight() / 2));
		glTexCoord2f(1, 1); glVertex2f((skin->GetWidth() / 2), (skin->GetHeight() / 2));
		glTexCoord2f(0, 1); glVertex2f(-(skin->GetWidth() / 2), (skin->GetHeight() / 2));
		glEnd();
	}

	glPopMatrix();

	glDisable(GL_BLEND);
}

void wxGLCanvasSubClass::DrawPlayer3D(int tex, Skin *skin, bool pickView)
{
	Point3Df vec (0, 0, 0);
	int count = 0;
	bool grass = !pickView && true/*grassToolStripMenuItem.Checked*/;

	for (size_t i = 0; i < CurrentModel->Meshes.size(); ++i)
	{
		if ((GlobalSettings::ViewFlags & CurrentModel->Meshes[i].Part) != 0)
		{
			vec += CurrentModel->Meshes[i].Translate;
			count++;
		}
	}

	if (count != 0)
		vec /= count;

	glTranslatef(0, 0, _3dZoom);
	glRotatef(_3dRotationX, 1, 0, 0);
	glRotatef(_3dRotationY, 0, 1, 0);

	glTranslatef(-vec.X, -vec.Y, 0);

	wxPoint clPt = ScreenToClient(wxGetMousePosition());
	float x = clPt.x - (_currentViewport.width / 2);
	float y = clPt.x - (_currentViewport.height / 2);

	if (!pickView && GlobalSettings::Transparency == TransparencyMode_All)
		glEnable(GL_BLEND);
	else
		glDisable(GL_BLEND);

	//if (grass)
	//	DrawSkinnedRectangle(0, -20, 0, 1024, 4, 1024, 0, 0, 1024, 1024, 0, 0, 0, 0, 0, 0, 1024, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _grassTop, 16, 16);

	Point3Df helmetRotate = (GlobalSettings::FollowCursor) ? Point3Df((float)y / 25, (float)x / 25, 0) : Point3Df(0, 0, 0);
	double sinAnim = (GlobalSettings::Animate) ? sinf(_animationTime) : 0;

	// draw non-transparent meshes
	for (size_t i = 0; i < CurrentModel->Meshes.size(); ++i)
	{
		Mesh &mesh = CurrentModel->Meshes[i];
		if (mesh.Helmet)
			continue;
		if ((GlobalSettings::ViewFlags & mesh.Part) == 0)
			continue;

		Mesh newMesh(mesh);

		newMesh.Texture = tex;

		if (mesh.FollowCursor && GlobalSettings::FollowCursor)
			newMesh.Rotate = helmetRotate;

		for (size_t f = 0; f < newMesh.Faces.size(); ++f)
			for (size_t c = 0; c < newMesh.Faces[f].Colors.size(); ++c)
				newMesh.Faces[f].Colors[c] = Colorb(255, 255, 255, 255);

		if (GlobalSettings::Animate && mesh.RotateFactor != 0)
			newMesh.Rotate += Point3Df((float)sinAnim * mesh.RotateFactor, 0, 0);

		_renderer->Meshes.push_back(newMesh);
	}

	_renderer->Render();

	// Draw ghosted parts
	if (GlobalSettings::Ghost && !pickView)
	{
		for (size_t i = 0; i < CurrentModel->Meshes.size(); ++i)
		{
			Mesh &mesh = CurrentModel->Meshes[i];
			if (mesh.Helmet)
				continue;
			if ((GlobalSettings::ViewFlags & mesh.Part) != 0)
				continue;

			Mesh newMesh(mesh);

			newMesh.Texture = tex;

			if (mesh.FollowCursor && GlobalSettings::FollowCursor)
				newMesh.Rotate = helmetRotate;

			for (size_t f = 0; f < newMesh.Faces.size(); ++f)
				for (size_t c = 0; c < newMesh.Faces[f].Colors.size(); ++c)
					newMesh.Faces[f].Colors[c] = Colorb(255, 255, 255, 255);

			if (GlobalSettings::Animate && mesh.RotateFactor != 0)
				newMesh.Rotate += Point3Df((float)sinAnim * mesh.RotateFactor, 0, 0);

			_renderer->Meshes.push_back(newMesh);
		}

		glEnable(GL_BLEND);
		_renderer->Render();
		glDisable(GL_BLEND);
	}

	if (!pickView && GlobalSettings::Transparency != TransparencyMode_Off)
		glEnable(GL_BLEND);
	else
		glDisable(GL_BLEND);

	// draw helmet meshes
	for (size_t i = 0; i < CurrentModel->Meshes.size(); ++i)
	{
		Mesh &mesh = CurrentModel->Meshes[i];
		if (!mesh.Helmet)
			continue;
		if ((GlobalSettings::ViewFlags & mesh.Part) == 0)
			continue;

		Mesh newMesh(mesh);

		newMesh.Texture = tex;

		if (mesh.FollowCursor && GlobalSettings::FollowCursor)
			newMesh.Rotate = helmetRotate;

		for (size_t f = 0; f < newMesh.Faces.size(); ++f)
			for (size_t c = 0; c < newMesh.Faces[f].Colors.size(); ++c)
				newMesh.Faces[f].Colors[c] = Colorb(255, 255, 255, 255);

		if (GlobalSettings::Animate && mesh.RotateFactor != 0)
			newMesh.Rotate += Point3Df((float)sinAnim * mesh.RotateFactor, 0, 0);

		_renderer->Meshes.push_back(newMesh);
	}

	_renderer->Render();

	// Draw ghosted parts
	if (GlobalSettings::Ghost && !pickView)
	{
		for (size_t i = 0; i < CurrentModel->Meshes.size(); ++i)
		{
			Mesh &mesh = CurrentModel->Meshes[i];
			if (!mesh.Helmet)
				continue;
			if ((GlobalSettings::ViewFlags & mesh.Part) != 0)
				continue;

			Mesh newMesh(mesh);

			newMesh.Texture = tex;

			if (mesh.FollowCursor && GlobalSettings::FollowCursor)
				newMesh.Rotate = helmetRotate;

			for (size_t f = 0; f < newMesh.Faces.size(); ++f)
				for (size_t c = 0; c < newMesh.Faces[f].Colors.size(); ++c)
					newMesh.Faces[f].Colors[c] = Colorb(255, 255, 255, 255);

			if (GlobalSettings::Animate && mesh.RotateFactor != 0)
				newMesh.Rotate += Point3Df((float)sinAnim * mesh.RotateFactor, 0, 0);

			_renderer->Meshes.push_back(newMesh);
		}

		glEnable(GL_BLEND);
		_renderer->Render();
		glDisable(GL_BLEND);
	}
}

void wxGLCanvasSubClass::SetPreview()
{
	if (_lastSkin == NULL)
	{
		int tempArray[64 * 32];
		BindTexture(_previewPaint);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempArray);
	}
	else
	{
		Skin *skin = _lastSkin;

		BindTexture(CurrentSkin);

		fixedarray<int> tempArray (skin->GetWidth() * skin->GetHeight());
		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempArray);

		/*Point2Di p(-1, -1);

		var pick = GetPick(_mousePoint.X, _mousePoint.Y, ref p);
		{
			if (_selectedTool.Tool.RequestPreview(tempArray, skin, p.X, p.Y))
			{
				RenderState.BindTexture(_previewPaint);
				GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, skin.Width, skin.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, tempArray);
			}
			else
			{
				RenderState.BindTexture(_previewPaint);
				GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, skin.Width, skin.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, tempArray);
			}
		}*/
	}
}

void wxGLCanvasSubClass::Render()
{
	MakeCurrent();

	if(!IsShown()) return;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor4f(1, 1, 1, 1);

	SetPreview();

	switch (CurrentViewMode)
	{
	case ViewMode_Orthographic:
		Setup2D(wxRect(0, 0, GetSize().x, GetSize().y));
		DrawPlayer2D(_previewPaint, _lastSkin, false);
		break;
	case ViewMode_Perspective:
		Setup3D(wxRect(0, 0, GetSize().x, GetSize().y));
		DrawPlayer3D(_previewPaint, _lastSkin, false);
		break;
	case ViewMode_Hybrid:
		{
			int halfHeight = (int)ceil(GetSize().y / 2.0f);

			Setup3D(wxRect(0, 0, GetSize().x, halfHeight));
			DrawPlayer3D(_previewPaint, _lastSkin, false);

			Setup2D(wxRect(0, halfHeight, GetSize().x, halfHeight));
			DrawPlayer2D(_previewPaint, _lastSkin, false);
		}
		break;
	}

	glFlush();
	SwapBuffers();
}

IMPLEMENT_APP(MCSkinnerMultiApp);

void MyFrame1::m_splitter2OnSplitterSashPosChanging( wxSplitterEvent& event )
{
	event.Skip(true);
}

void MyFrame1::frameShow(wxShowEvent& event)
{
}

void MyFrame1::SetCanSave(bool dirty)
{
}

void MyFrame1::CheckUndo()
{
	bool canUndo = false;
	if (m_glCanvas->GetCurrentUndoBuffer() != NULL)
		canUndo = m_glCanvas->GetCurrentUndoBuffer()->CanUndo();

	m_undoToolButton->GetToolBar()->EnableTool(wxID_UNDO, canUndo);
	m_redoToolButton->GetToolBar()->EnableTool(wxID_REDO, canUndo);
	editRedoMenuItem->Enable(canUndo);
	editUndoMenuItem->Enable(canUndo);
}

void MyFrame1::m_treeCtrlItemChanged(wxTreeEvent &ev)
{
	if (m_treeCtrl1->GetItemData(ev.GetItem()) == NULL)
		return;

	Skin *skin = (Skin*)m_treeCtrl1->GetItemData(ev.GetItem());

	if (_skipListbox || m_glCanvas->_lastSkin == skin)
		return;

	if (m_glCanvas->_lastSkin != NULL && skin != m_glCanvas->_lastSkin)
	{
		// Copy over the current changes to the tex stored in the skin.
		// This allows us to pick up where we left off later, without undoing any work.
		m_glCanvas->_lastSkin->CommitChanges(CurrentSkin, false);
	}

	//if (_lastSkin != null)
	//	_lastSkin.Undo.Clear();

	m_glCanvas->_lastSkin = skin;
	m_glCanvas->MakeCurrent();

	SetCanSave(skin->Dirty);

	if (skin == NULL)
	{
		BindTexture(0);
		int arr[64 * 32];
		BindTexture(CurrentSkin);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, arr);
	
		CheckUndo();
	}
	else
	{
		BindTexture(skin->GLImage);
		int *tempArr = new int[skin->GetWidth() * skin->GetHeight()];
		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempArr);
		BindTexture(CurrentSkin);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, skin->GetWidth(), skin->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tempArr);
		BindTexture(m_glCanvas->_previewPaint);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, skin->GetWidth(), skin->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tempArr);
		
		CheckUndo();
		delete tempArr;
	}

	m_glCanvas->Render();
}

void SetViewMode(ViewMode newMode)
{
	frame->m_toolBar6->ToggleTool(TOOL_PERSPECTIVE, false);
	frame->m_toolBar6->ToggleTool(TOOL_ORTHOGRAPHIC, false);
	frame->m_toolBar6->ToggleTool(TOOL_HYBRID, false);
	frame->viewModePerspectiveMenuItem->Check(false);
	frame->viewModeTextureMenuItem->Check(false);
	frame->viewModeHybridMenuItem->Check(false);
	glCanvas->CurrentViewMode = newMode;

	switch (glCanvas->CurrentViewMode)
	{
	case ViewMode_Perspective:
		frame->m_toolBar6->ToggleTool(TOOL_PERSPECTIVE, true);
		frame->viewModePerspectiveMenuItem->Check(true);
		break;
	case ViewMode_Orthographic:
		frame->m_toolBar6->ToggleTool(TOOL_ORTHOGRAPHIC, true);
		frame->viewModeTextureMenuItem->Check(true);
		break;
	case ViewMode_Hybrid:
		frame->m_toolBar6->ToggleTool(TOOL_HYBRID, true);
		frame->viewModeHybridMenuItem->Check(true);
		break;
	}
}

void MyFrame1::OnViewToolBarItemClicked(wxCommandEvent &ev)
{
	if (ev.GetId() >= TOOL_BACKGROUND_ITEM && ev.GetId() <= TOOL_BACKGROUND_ITEM_MAX)
	{
		BackgroundMenuItem *item = (BackgroundMenuItem*)frame->view2DOverlayMenuItem->FindChildItem(ev.GetId());
		glCanvas->_currentBackground->Check(false);

		item->Check(true);
		glCanvas->_currentBackground = item;
		return;
	}

	switch (ev.GetId())
	{
	case TOOL_PERSPECTIVE:
		SetViewMode(ViewMode_Perspective);
		break;
	case TOOL_ORTHOGRAPHIC:
		SetViewMode(ViewMode_Orthographic);
		break;
	case TOOL_HYBRID:
		SetViewMode(ViewMode_Hybrid);
		break;
	}
}

bool MCSkinnerMultiApp::OnInit()
{
	wxInitAllImageHandlers();

	frame = new MyFrame1(0L);
	wxIconBundle bundle(RESOURCE(Icon_new, ico));
	frame->SetIcons(bundle); // To Set App Icon

	glCanvas = frame->m_glCanvas = new wxGLCanvasSubClass(frame->m_panel2);
	frame->bSizer15->Add( frame->m_glCanvas, 1, wxEXPAND, 5 );

	frame->_repaintTimer = new RepaintTimer(frame->m_glCanvas);
	frame->_repaintTimer->Start(13);
	frame->Show();

	frame->m_glCanvas->InitGL();

	for (boost::filesystem3::recursive_directory_iterator end, dir("./Models/"); dir != end; ++dir)
		if (boost::filesystem3::is_regular_file((*dir).path()))
			CurrentModel = Model::Load((*dir).path().string());

	wxTreeItemId root = frame->m_treeCtrl1->AddRoot("Skins");

	for (boost::filesystem3::directory_iterator end, dir("./Skins/"); dir != end; ++dir)
	{
		if (boost::filesystem3::is_regular_file((*dir).path()))
		{
			wxTreeItemId id = frame->m_treeCtrl1->AppendItem(root, (*dir).path().filename().stem().string());
			Skin *skin = new Skin((*dir).path().string(), frame->m_treeCtrl1, id);
			skin->SetImages();
		}
		else if (boost::filesystem3::is_directory((*dir).path()))
		{
			wxTreeItemId parentId = frame->m_treeCtrl1->AppendItem(root, (*dir).path().stem().string());
			RecurseAddItems(frame->m_treeCtrl1, parentId, (*dir).path());
		}
	}

	SetViewMode(ViewMode_Perspective);

	return true;
}
